﻿namespace Pyramid
{

    /// <summary>
    /// Represents a 27-trit balanced ternary integer.
    /// </summary>
    public struct Int27
        : ITernary
    {
        /// <summary>
        /// The maximum numeric value that a Int27 can store.
        /// </summary>
        private const long MAX_VALUE = 3812798742493; //(3 ^ 27 - 1) / 2

        /// <summary>
        /// The minimum numeric value that a Int27 can store.
        /// </summary>
        private const long MIN_VALUE = -MAX_VALUE;

        /// <summary>
        /// Represents the largest possible value of a
        /// <see cref="Setun.Int27"/>. This field is read-only.
        /// </summary>
        public static readonly Int27 MaxValue = new Int27(MAX_VALUE);

        /// <summary>
        /// Represents the smallest possible value of a
        /// <see cref="Setun.Int27"/>. This field is read-only.
        /// </summary>
        public static readonly Int27 MinValue = new Int27(MIN_VALUE);

        public const int TritsPerInt27 = 27;

        private readonly long value;

        private Int27(long value)
        {
            Util.AssertRange(value, MIN_VALUE, MAX_VALUE);

            this.value = value;
        }

        public Trivalent[] ToTritArray()
        {
            return Util.ToTritArray(this.value, TritsPerInt27);
        }

        public Tryte ToTryte()
        {
            return (Tryte)this.value;
        }

        public Int27 ToInt27()
        {
            return this;
        }

        public int TritSize
        {
            get
            {
                return TritsPerInt27;
            }
        }

        public static implicit operator Int27(byte value)
        {
            return new Int27(value);
        }

        public static explicit operator byte(Int27 value)
        {
            return (byte)value.value;
        }

        public static implicit operator Int27(short value)
        {
            return new Int27(value);
        }

        public static explicit operator short(Int27 value)
        {
            return (short)value.value;
        }

        public static implicit operator Int27(int value)
        {
            return new Int27(value);
        }

        public static explicit operator int(Int27 value)
        {
            return (int)value.value;
        }

        public static implicit operator Int27(long value)
        {
            return new Int27(Util.Trim(value, MAX_VALUE, MIN_VALUE));
        }

        public static implicit operator long(Int27 value)
        {
            return value.value;
        }

        public override string ToString()
        {
            return value.ToString();
        }
    }
}